package cn.stylefeng.guns.base.utils;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;

import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 字符工具类
 *
 * @author xieshengmeng
 * @create 2018-01-10 上午 11:56
 **/
public class StringUtil {

    /**
     * 判断对象是否为null,不允许空白串
     *
     * @param object 目标对象类型
     * @return
     */
    public static boolean isNull(Object object) {
        if (null == object) {
            return true;
        }
        if ("null".equals(object)) {
            return true;
        }
        if ("undefined".equals(object)) {
            return true;
        }
        if ((object instanceof String)) {
            return "".equals(((String) object).trim());
        }
        return false;
    }

    /**
     * 判断对象是否不为null
     *
     * @param object
     * @return
     */
    public static boolean isNotNull(Object object) {
        return !isNull(object);
    }

    /**
     * @param length
     * @return
     */
    public static String getStringRandom(int length) {

        String val = "";
        Random random = new Random();

        //参数length，表示生成几位随机数
        for (int i = 0; i < length; i++) {

            String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";
            //输出字母还是数字
            if ("char".equalsIgnoreCase(charOrNum)) {
                //输出是大写字母还是小写字母
                int temp = random.nextInt(2) % 2 == 0 ? 65 : 97;
                val += (char) (random.nextInt(26) + temp);
            } else if ("num".equalsIgnoreCase(charOrNum)) {
                val += String.valueOf(random.nextInt(10));
            }
        }
        return val;
    }

    public static Integer getIntForString(String str) {
        String regEx = "[^0-9]";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(str);
        return Integer.valueOf(m.replaceAll("").trim());
    }


    //判断尾部数值 去除多余位数
    public static String delZero(String num) {
        if (num.endsWith("0")) {
            num = num.substring(0, num.length() - 1);
        }
        return num;
    }

    /**
     * 计算出下个流水号
     *
     * @param seq
     * @return
     */
    public static final String calNextSeq(String seq) {
        StringBuilder next = new StringBuilder(seq.length());
        Integer temp = Integer.valueOf(seq);
        temp++;
        String t = temp.toString();
        if (t.length() < seq.length()) {
            for (int i = 0; i < seq.length() - t.length(); i++) {
                next.append("0");
            }
        }
        next.append(t);
        return next.toString();
    }


    /**
     * 全角转半角
     *
     * @param string
     * @return
     */
    public static String full2Half(String string) {
        if (isNull(string)) {
            return string;
        }
        char[] charArray = string.toCharArray();
        for (int i = 0; i < charArray.length; i++) {
            if (charArray[i] == 12288) {
                charArray[i] = ' ';
            } else if (charArray[i] >= ' ' && charArray[i] <= 65374) {
                charArray[i] = (char) (charArray[i] - 65248);
            }
        }
        return new String(charArray);
    }

    public static final String full2HalfChange(String QJstr) throws UnsupportedEncodingException {
        StringBuffer outStrBuf = new StringBuffer("");
        String Tstr = "";
        byte[] b = null;
        for (int i = 0; i < QJstr.length(); i++) {
            Tstr = QJstr.substring(i, i + 1);
            // 全角空格转换成半角空格
            if (Tstr.equals("　")) {
                outStrBuf.append(" ");
                continue;
            }
            b = Tstr.getBytes("unicode");
            // 得到 unicode 字节数据
            if (b[2] == -1) {
                // 表示全角？
                b[3] = (byte) (b[3] + 32);
                b[2] = 0;
                outStrBuf.append(new String(b, "unicode"));
            } else {
                outStrBuf.append(Tstr);
            }
        } // end for.
        return outStrBuf.toString();
    }

    public static String getEncoding(String str) {
        String encode = "GB2312";
        try {
            if (str.equals(new String(str.getBytes(encode), encode))) {      //判断是不是GB2312
                String s = encode;
                return s;      //是的话，返回“GB2312“，以下代码同理
            }
        } catch (Exception exception) {
        }
        encode = "ISO-8859-1";
        try {
            if (str.equals(new String(str.getBytes(encode), encode))) {      //判断是不是ISO-8859-1
                String s1 = encode;
                return s1;
            }
        } catch (Exception exception1) {
        }
        encode = "UTF-8";
        try {
            if (str.equals(new String(str.getBytes(encode), encode))) {   //判断是不是UTF-8
                String s2 = encode;
                return s2;
            }
        } catch (Exception exception2) {
        }
        encode = "GBK";
        try {
            if (str.equals(new String(str.getBytes(encode), encode))) {      //判断是不是GBK
                String s3 = encode;
                return s3;
            }
        } catch (Exception exception3) {
        }
        return "";
    }


    /**
     * 比较两个字符串的相识度
     * 核心算法：用一个二维数组记录每个字符串是否相同，如果相同记为0，不相同记为1，每行每列相同个数累加
     * 则数组最后一个数为不相同的总数，从而判断这两个字符的相识度
     *
     * @param str
     * @param target
     * @return
     */
    private static int compare(String str, String target) {
        int d[][];              // 矩阵
        int n = str.length();
        int m = target.length();
        int i;                  // 遍历str的
        int j;                  // 遍历target的
        char ch1;               // str的
        char ch2;               // target的
        int temp;               // 记录相同字符,在某个矩阵位置值的增量,不是0就是1
        if (n == 0) {
            return m;
        }
        if (m == 0) {
            return n;
        }
        d = new int[n + 1][m + 1];
        // 初始化第一列
        for (i = 0; i <= n; i++) {
            d[i][0] = i;
        }
        // 初始化第一行
        for (j = 0; j <= m; j++) {
            d[0][j] = j;
        }
        for (i = 1; i <= n; i++) {
            // 遍历str
            ch1 = str.charAt(i - 1);
            // 去匹配target
            for (j = 1; j <= m; j++) {
                ch2 = target.charAt(j - 1);
                if (ch1 == ch2 || ch1 == ch2 + 32 || ch1 + 32 == ch2) {
                    temp = 0;
                } else {
                    temp = 1;
                }
                // 左边+1,上边+1, 左上角+temp取最小
                d[i][j] = min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + temp);
            }
        }
        return d[n][m];
    }


    /**
     * 获取最小的值
     */
    private static int min(int one, int two, int three) {
        return (one = one < two ? one : two) < three ? one : three;
    }

    /**
     * 获取两字符串的相似度
     */
    public static float getSimilarityRatio(String str, String target) {
        int max = Math.max(str.length(), target.length());
        return 1 - (float) compare(str, target) / max;
    }


    /**
     * public int indexOf(int ch, int fromIndex)
     * 返回在此字符串中第一次出现指定字符处的索引，从指定的索引开始搜索
     *
     * @param srcText
     * @param findText
     * @return
     */
    public static Double appearNumber(String srcText, String findText) {
        byte[] bytes = findText.getBytes();
        int i = 0;
        for (int k = 0; k < findText.length(); k++) {
            String str = findText.substring(k, k + 1);
            if (srcText.indexOf(str) != -1) {
                i++;
            }
        }
        return i * 1.0 / findText.length();
    }

    /**
     * 检测两个字符串同一个位置相同字符的个数，前提是两个字符位数相等
     *
     * @param str1 字符1
     * @param str2 字符2
     * @return
     */
    public static int checkTwoStringSameNum(String str1, String str2) {
        int k = 0;
        for (int i = 0; i < str1.length(); i++) {
            if (str1.charAt(i) == str2.charAt(i)) {
                k++;
            }
        }
        return k;
    }


    /**
     * 检测两个名字是否存在脱敏关系
     * <p>
     * 张三丰，张王丰--true
     * 张三丰，张王八--true
     * 张三丰，张丰--true
     * 张三丰，张三--true
     * 张三丰，三丰--true
     * 张三丰，王丰--true
     * 独狐求败，张求败--true
     * 独狐求败，败张--false
     *
     * @param name1
     * @param name2
     * @return
     */
    public static boolean checkTwoNameHasTuoMing(String name1, String name2) {
        if (Objects.equals(name1, name2)) {
            return false;
        }
        if (name1.length() == name2.length()) {
            return checkTwoStringSameNum(name1, name2) > 0;
        }
        if (name1.contains(name2) || name2.contains(name1)) {
            return true;
        }
        String maxName = name1;
        String minName = name2;
        if (name1.length() < name2.length()) {
            maxName = name2;
            minName = name1;
        }
        int index = 0;
        for (int i = 0; i < minName.length(); i++) {
            index = maxName.indexOf(String.valueOf(minName.charAt(i)));
            if (index != -1 && index != maxName.length() - 1) {
                return true;
            }
        }
        return false;
    }

    /**
     * 生成随机的字母+数字的组合
     *
     * @param length
     * @return
     */
    public static String digitalAlphabetRandom(int length) {
        String val = "";
        Random random = new Random();

        //参数length，表示生成几位随机数
        for (int i = 0; i < length; i++) {
            //随机数由0-9，a-z,A-Z组成，数字占10个，字母占52个，数字、字母占比1:5（标准的应该是10:52）
            //random.nextInt(6) 0-5中6个数取一个
            String charOrNum = (random.nextInt(6) + 6) % 6 >= 1 ? "char" : "num";
            //输出字母还是数字
            if ("char".equalsIgnoreCase(charOrNum)) {
                //输出是大写字母还是小写字母，输出比例为1:1
                int temp = random.nextInt(2) % 2 == 0 ? 97 : 65;
                //char（65）-char(90) 为大写字母A-Z；char(97)-char(122)为小写字母a-z
                val += (char) (random.nextInt(26) + temp);
            } else if ("num".equalsIgnoreCase(charOrNum)) {
                val += String.valueOf(random.nextInt(10));
            }
        }
        return val;

    }

    /**
     * @Description: 手机号、身份证号、姓名脱敏
     * @Author: xiesm
     * @Date: 2019/5/29 16:59
     */
    public static String parse(JSONObject jsonObject, String[] mobiles, String[] idNos, String[] names, String[] bankcards) {
        Set<String> keys = jsonObject.keySet();
        for (String key : keys) {
            if ((jsonObject.getString(key) != null && jsonObject.get(key) instanceof JSONObject)
                    || StringUtil.isNotNull(jsonObject.get(key)) && jsonObject.getString(key).startsWith("{")) {
                jsonObject.put(key, parse(jsonObject.getJSONObject(key), mobiles, idNos, names, bankcards));
            } else if ((jsonObject.getString(key) != null && jsonObject.get(key) instanceof JSONArray)
                    || StringUtil.isNotNull(jsonObject.get(key)) && jsonObject.getString(key).startsWith("[")) {
                JSONArray jsonArray = jsonObject.getJSONArray(key);
                for (int i = 0; i < jsonArray.size(); i++) {
                    if (jsonArray.get(i) instanceof JSONObject) {
                        parse(jsonArray.getJSONObject(i), mobiles, idNos, names, bankcards);
                    }
                }
            } else {
                //脱敏手机
                if (StringUtil.isNotNull(mobiles) && mobiles.length > 0) {
                    for (String mobile : mobiles) {
                        if (Objects.equals(key, mobile)) {
                            String value = jsonObject.getString(key);
                            jsonObject.put(key, dataConceal4Mobile(value));
                        }
                    }
                }
                //脱敏身份证
                if (StringUtil.isNotNull(idNos) && idNos.length > 0) {
                    for (String idNo : idNos) {
                        if (Objects.equals(key, idNo)) {
                            String value = jsonObject.getString(key);
                            jsonObject.put(key, dataConceal4IdNo(value));
                        }
                    }
                }
                //脱敏姓名
                if (StringUtil.isNotNull(names) && names.length > 0) {
                    for (String name : names) {
                        if (Objects.equals(key, name)) {
                            String value = jsonObject.getString(key);
                            jsonObject.put(key, dataConceal4Name(value));
                        }
                    }
                }
                //脱敏银行卡
                if (StringUtil.isNotNull(bankcards) && bankcards.length > 0) {
                    for (String bankcard : bankcards) {
                        if (Objects.equals(key, bankcard)) {
                            String value = jsonObject.getString(key);
                            jsonObject.put(key, dataConceal4Bankcard(value));
                        }
                    }
                }
            }
        }
        return jsonObject.toJSONString();
    }

    /**
     * @Description: 脱敏手机号
     * @Author: xiesm
     * @Date: 2019/5/18 16:49
     */
    private static String dataConceal4Mobile(String mobile) {
        if (mobile.length() != 11) {
            return mobile;
        }
        StringBuilder sb = new StringBuilder();
        sb.append(mobile.substring(0, 3));
        sb.append("****").append(mobile.substring(7));
        return sb.toString();
    }

    /**
     * @Description: 脱敏身份证号
     * @Author: xiesm
     * @Date: 2019/5/18 16:49
     */
    private static String dataConceal4IdNo(String idNo) {
        if (idNo.length() != 18) {
            return idNo;
        }
        StringBuilder sb = new StringBuilder();
        sb.append(idNo.substring(0, 6));
        sb.append("********").append(idNo.substring(14, 17)).append("*");
        return sb.toString();
    }

    /**
     * @Description: 脱敏姓名
     * @Author: xiesm
     * @Date: 2019/5/18 16:49
     */
    private static String dataConceal4Name(String name) {
        if (name.length() == 1 || !isChinese(name)) {
            return name;
        }
        StringBuilder sb = new StringBuilder();
        if (name.length() == 2) {
            sb.append(name.substring(0, 1)).append("*");
        } else if (name.length() == 3) {
            sb.append(name.substring(0, 1)).append("**");
        } else {
            sb.append(name.substring(0, 2));
            for (int i = 0; i < name.length() - 2; i++) {
                sb.append("*");
            }
        }
        return sb.toString();
    }

    /**
     * @Description: 脱敏银行卡
     * @Author: xiesm
     * @Date: 2019/5/18 16:49
     */
    private static String dataConceal4Bankcard(String bankcard) {
        if (bankcard.length() < 14) {
            return bankcard;
        }
        StringBuilder sb = new StringBuilder();
        sb.append(bankcard.substring(0, 4));
        sb.append("********").append(bankcard.substring(bankcard.length() - 4));
        return sb.toString();
    }

    /**
     * 完整的判断中文汉字和符号
     *
     * @param strName
     * @return
     */
    public static boolean isChinese(String strName) {
        if (strName.contains("＊")) {
            return false;
        }
        char[] ch = strName.toCharArray();
        for (int i = 0; i < ch.length; i++) {
            char c = ch[i];
            if (!isChinese(c)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 根据Unicode编码完美的判断中文汉字和符号
     *
     * @param c
     * @return
     */
    private static boolean isChinese(char c) {
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
        if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
                || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
                || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS
                || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION) {
            return true;
        }
        return false;
    }

    public static void main(String[] args) {
        boolean chinese = isChinese("**军");
        System.out.println(chinese);
    }

    /**
     * @Description: 判断两个姓名脱敏是否未脱敏部分是否匹配，
     * 周*星---周** = 匹配
     * 周*星---**周 = 匹配
     * 周*星---*星 = 不匹配
     * @Author: xiesm
     * @Date: 2019/6/6 10:25
     */
    public static boolean decideConcealNameMatch(String str1, String str2) {
        if (str1.length() != str2.length()) {
            return false;
        }
        int j = 0, k = 0;
        for (int i = 0; i < str1.split("").length; i++) {
            String[] strs1 = str1.split("");
            String[] strs2 = str2.split("");
            if (StringUtil.isChinese(strs1[i]) && StringUtil.isChinese(strs2[i])) {
                j++;
                if (Objects.equals(strs1[i], strs2[i])) {
                    k++;
                }
            }
        }
        return j == k;
    }

    /**
     * 方法描述：获取List中优先级最高的元素
     *
     * @param list
     * @param element
     * @return
     */
    public static Map<String, Object> getMaxPriority(Set<Map<String, Object>> list, String element) {
        Map<String, Map<String, Object>> result = new HashMap();
        List<String> sortList = new ArrayList();
        for (Map<String, Object> map : list) {
            if (map.get(element) != null) {
                String str = encapsulation(0, "_" + map.get(element), ((Map) map.get(element)).get("priority"));
                sortList.add(str);
                result.put(str, (Map) map.get(element));
            }
        }
        Collections.sort(sortList);
        return result.get(sortList.get(sortList.size() - 1));
    }

    /**
     * 方法描述：获取List中最多的的元素
     *
     * @param list
     * @param element 元素名称
     * @return
     */
    public static Map<String, Object> getMostFromList(Set<Map<String, Object>> list, String element, String flag) {
        Map<String, Map<String, Object>> result = new HashMap();
        Map<String, Integer> paramMap = new HashMap();
        List<String> sortList = new ArrayList();
        //第一次循环先判断相同参数的个数
        for (Map<String, Object> map : list) {
            if (map.get(element) != null) {
                String param = ((Map) map.get(element)).get(flag).toString();
                if (paramMap.containsKey(param)) {
                    Integer num = paramMap.get(param) + 1;
                    paramMap.put(param, num);
                } else {
                    paramMap.put(param, 1);
                }
            }
        }
        //第二次循环根据数量和优先级排序
        for (Map<String, Object> map : list) {
            if (map.get(element) != null) {
                String param = ((Map) map.get(element)).get(flag).toString();
                Integer num = paramMap.remove(param);
                paramMap.put(param, num);
                String str = encapsulation(num, "_" + param, ((Map) map.get(element)).get("priority"));
                sortList.add(str);
                result.put(str, (Map) map.get(element));
            }
        }
        Collections.sort(sortList);
        return result.get(sortList.get(sortList.size() - 1));
    }

    /**
     * 方法描述：整理成对应的数据结构num_element
     *
     * @param codeNum  出现次数
     * @param codeName 元素名称
     * @return
     */
    public static String encapsulation(Integer codeNum, String codeName, Object priority) {
        String codeString = null;
        if (codeNum <= 9) {
            codeString = "00" + codeNum + priority + codeName;
        } else if (codeNum <= 99) {
            codeString = "0" + codeNum + priority + codeName;
        } else if (codeNum <= 999) {
            codeString = "" + codeNum + priority + codeName;
        }
        return codeString;
    }

    /**
     * 方法描述：字符串根据ASCII码表进行升序排列
     *
     * @param str 原字符串
     * @return 排序后的字符串
     */
    public static String ASCIISort(String str) {
        char[] test = new char[str.length()];
        StringBuilder sb = new StringBuilder();
        while (true) {
            String a = str;//直接读取这行当中的字符串。
            for (int i = 0; i < str.length(); i++) {
                test[i] = a.charAt(i);//字符串处理每次读取一位。
            }
            Arrays.sort(test);
            for (int i = 0; i < test.length; i++) {
                sb.append(test[i]);
            }
            String trim = sb.toString().trim();
            return trim;
        }
    }

    /**
     * 方法描述：中文转unicode编码
     *
     * @param str 原字符串
     * @return
     */
    public static String chineseToUnicode(String str) {
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < str.length(); i++) {
            int chr1 = (char) str.charAt(i);
            if (chr1 >= 19968 && chr1 <= 171941) {//汉字范围 \u4e00-\u9fa5 (中文)
                result.append("\\u").append(String.valueOf(Integer.toHexString(chr1)));
            } else {
                result.append(str.charAt(i));
            }
        }
        return result.toString();
    }

    /**
     * 方法描述：unicode转中文编码
     *
     * @param str 原字符串
     * @return
     */
    public static String unicodeToString(String str) {
        Pattern pattern = Pattern.compile("(\\\\u(\\p{XDigit}{4}))");
        Matcher matcher = pattern.matcher(str);
        char ch;
        while (matcher.find()) {
            ch = (char) Integer.parseInt(matcher.group(2), 16);
            str = str.replace(matcher.group(1), ch + "");
        }
        return str;
    }

    /**
     * 解析地址
     *
     * @param address
     * @return
     * @author lin
     */
    private static String regex = "(?<province>[^省]+自治区|.*?省|.*?行政区|.*?市)(?<city>[^市]+自治州|.*?地区|.*?行政单位|.+盟|市辖区|.*?市|.*?县)(?<county>[^县]+县|.+区|.+市|.+旗|.+海域|.+岛)?(?<town>[^区]+区|.+镇)?(?<village>.*)";

    public static List<Map<String, String>> addressResolution(String address) {
        Matcher m = Pattern.compile(regex).matcher(address);
        String province, city, county, town, village;
        List<Map<String, String>> table = new ArrayList<>();
        Map<String, String> row;
        while (m.find()) {
            row = new LinkedHashMap<>();
            province = m.group("province");
            row.put("province", province == null ? "" : province.trim());
            city = m.group("city");
            row.put("city", city == null ? "" : city.trim());
            county = m.group("county");
            row.put("county", county == null ? "" : county.trim());
            town = m.group("town");
            row.put("town", town == null ? "" : town.trim());
            village = m.group("village");
            row.put("village", village == null ? "" : village.trim());
            table.add(row);
        }
        return table;
    }

    public static void sortMap(Map<String, Integer> map) {
        Map<String, Integer> map2 = Maps.newLinkedHashMap();
        List<Map.Entry<String, Integer>> infos = new ArrayList<>(map.entrySet());
        infos.sort((t0, t1) -> t1.getValue() - t0.getValue());
        Iterator<Map.Entry<String, Integer>> iterator = infos.iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Integer> next = iterator.next();
            map2.put(next.getKey(), next.getValue());
        }
        map.clear();
        map.putAll(map2);
    }

    public static String getMap4Num(Map<String, Integer> map, int num) {
        Iterator<String> iterator = map.keySet().iterator();
        int count = 1;
        while (iterator.hasNext()) {
            String next = iterator.next();
            if (count++ == num) {
                return next;
            }
        }
        return null;
    }

    public static String getMap4Num2(Map<String, Integer> map, int num) {
        Iterator<String> iterator = map.keySet().iterator();
        int count = 1;
        while (iterator.hasNext()) {
            String next = iterator.next();
            Integer val = map.get(next);
            if (count++ == num) {

                return next + ":" + val;
            }
        }
        return null;
    }

    public static List<String> replace(String str, String flag) {
        str = str.replace(flag, "")
                .replace("'", "")
                .replace("(", "")
                .replace(")", "");
        return Arrays.asList(str.split(","));
    }
}
